JS this指向

JS中的this指向问题,及解决方法

问题

function A() {}
A.prototype.fna = function() {
    console.log(this);
}

this指向

var a = new A();
a.fna();  // A {}

var fnt = a.fna;
fnt();  // window {...}

以及

1
2
3
4
5
6
7
8
9
10
11
12
13
14
function A() {
this.name = 'A';
}

A.prototype.fna = function() {
return this.name;
}

function sayName(fn) {
console.log(fn());
}

sayName(a.fna); //undefined
sayName(a.fna.bind(a)); //A

再来一波

  1. 当this关键字在一个声明对象内部使用,其值会被绑定到调用该this的函数的最近的父对象。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    var person = {
    first: 'John',
    last: 'Smith',
    full: function() {
    console.log(this.first + ' ' + this.last);
    }
    };
    person.full();
    // 输出 'John Smith'

    在被声明的对象person中的full函数里面使用了this, 那么调用this的full函数的最近的父对象就是person, 因此,this指向person。
    多层嵌套中依旧生效

  2. new关键字,this直接绑定到这个新对象。

call, bind, 和apply

call()第一个参数是this需要绑定的对象,剩下的是add函数本来的参数。
add.apply()也类似,除了第二个参数是一个数组.
bind()函数和call()类似,但是bind()函数不会立即被调用。bind()函数会返回一个函数,并且将this绑定好。

1
2
3
4
5
6
7
8
9
10
11
12
13
var small = {
a: 1,
go: function(b,c,d){
console.log(this.a+b+c+d);
}
}

var large = {
a: 100
}

small.go(2, 3, 4);
// 输出 10

想使用large.a的值,可以使用call/apply:

small.go.call(large, 2, 3, 4);
// 输出 109

现在还不知道这三个参数应该传入什么值,可以使用bind:

var bindTest = small.go.bind(large, 2);

将bindTest在控制台下打印出来,我们会看到:

console.log(bindTest);
// 输出 function (b,c,d)

该函数已经将this绑定到large对象,并且传入了第一个参数b。所以,我们接下来是需要传入余下的参数即可

bindTest(3, 4);
// 输出 109

箭头函数(->)

无法得到预期

1
2
3
4
5
6
7
8
9
10
var obj = {
birth: 1990,
getAge: function () {
var b = this.birth; // 1990
var fn = function () {
return new Date().getFullYear() - this.birth; // this指向window或undefined
};
return fn();
}
};

箭头函数修复了this指向

1
2
3
4
5
6
7
8
9
var obj = {
birth: 1990,
getAge: function () {
var b = this.birth; // 1990
var fn = () => new Date().getFullYear() - this.birth; // this指向obj对象
return fn();
}
};
obj.getAge(); // 25

结论

  1. this的值通常是由当前函数的执行环境所决定;
  2. 在全局作用域,this指向全局对象 (window对象);
  3. 当使用new关键字声明,this指向新建对象;
  4. 我们可以使用call(), bind(), apply()来设置this;
  5. 箭头函数会绑定this。